package top.lingkang.ciyuanwaf.controller;

import cn.hutool.core.codec.Base64Decoder;
import cn.hutool.core.codec.Base64Encoder;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import lombok.extern.slf4j.Slf4j;
import org.noear.solon.annotation.Controller;
import org.noear.solon.annotation.Inject;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.core.handle.Context;
import org.noear.solon.core.handle.MethodType;
import org.noear.solon.core.handle.ModelAndView;
import top.lingkang.ciyuanwaf.WebApp;
import top.lingkang.ciyuanwaf.dao.ConfHistoryDao;
import top.lingkang.ciyuanwaf.dao.SettingDao;
import top.lingkang.ciyuanwaf.dto.ResponseResult;
import top.lingkang.ciyuanwaf.entity.SettingEntity;
import top.lingkang.ciyuanwaf.utils.CheckUtils;
import top.lingkang.ciyuanwaf.utils.CommonUtils;
import top.lingkang.ciyuanwaf.utils.terminal.OsUtils;
import top.lingkang.ciyuanwaf.utils.terminal.TerminalUtils;
import top.lingkang.hibernate6.transaction.Transaction;

import java.io.File;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

/**
 * @author lingkang
 * created by 2023/11/23
 */
@Slf4j
@Controller
@Mapping("/nginx")
public class NginxController {
    @Inject
    private SettingDao settingDao;
    @Inject
    private ConfHistoryDao confHistoryDao;

    /**
     * 获取nginx状态
     */
    @Mapping(value = "/nginxStatus", method = MethodType.GET)
    public Object nginxStatus() {
        return new ResponseResult<>().setData(TerminalUtils.nginxIsRun(WebApp.thread));
    }

    /**
     * 前往nginx配置页面
     */
    @Mapping(value = "/config", method = MethodType.GET)
    public Object config() {
        ModelAndView view = new ModelAndView("config.ftl");
        SettingEntity setting = settingDao.findAll().get(0);
        view.put("data", setting);
        view.put("nginxExistsUpdate", "true".equals(setting.getExistsUpdate()));
        return view;
    }

    /**
     * 绑定nginx配置
     */
    @Transaction
    @Mapping(value = "/config", method = MethodType.POST)
    public Object config(String path, String conf) {
        CheckUtils.checkNotEmpty(path, "nginx路径");
        File file = new File(path);
        if (!file.exists() || !file.isDirectory())
            return new ResponseResult<>().fail("nginx 目录不存在！");

        boolean has = false;
        for (String str : file.list())
            if (str.contains("nginx")) {
                has = true;
                break;
            }
        if (!has)
            return new ResponseResult<>().fail(path + " 目录不存在nginx二进制启动文件，该目录可能不是nginx所在路径");

        File nginxConf = CommonUtils.getItem(file, "conf", true);
        if (nginxConf == null || StrUtil.isNotBlank(conf)) {
            File temp = new File(conf);
            if (!temp.exists() || !temp.isDirectory()) {
                return new ResponseResult<>().fail("找不到conf目录：" + conf);
            }
            nginxConf = temp;
        }
        File nginx = CommonUtils.getItem(nginxConf, "nginx.conf", false);
        if (nginx == null)
            return new ResponseResult<>().fail("conf目录下找不到nginx.conf配置文件！");
        File confList = new File(nginxConf.getAbsolutePath() + File.separator + "confList");
        if (!confList.exists())
            confList.mkdirs();
        // 进入到nginx目录
        TerminalUtils.cdNginxDir(WebApp.thread, file.getAbsolutePath());
        ThreadUtil.sleep(500);

        File newNginx = new File(nginx.getAbsolutePath());
        // 备份
        File backNginx = new File(nginx.getAbsolutePath() + "-" + System.currentTimeMillis());
        nginx.renameTo(backNginx);
        InputStream in = getClass().getClassLoader().getResourceAsStream("template/nginx.conf");
        String read = IoUtil.read(in, StandardCharsets.UTF_8);
        String confListPath = "include " + confList.getAbsolutePath() + File.separator + "*.conf;";
        if (OsUtils.isWindow())//  D:\software\openresty-1.21.4.3-win64\confList\8080.conf window下斜杠需要改为 /
            confListPath = confListPath.replaceAll("\\\\", "/");
        read = read.replace("#wafinclude", confListPath);
        // 新配置文件
        FileUtil.writeString(read, newNginx, StandardCharsets.UTF_8);

        SettingEntity entity = settingDao.findAll().get(0);
        entity.setNginxPath(file.getAbsolutePath());
        entity.setIsInit("true");
        entity.setOldName(backNginx.getName());
        entity.setConfPath(nginxConf.getAbsolutePath());
        entity.setConfList(confList.getAbsolutePath());
        File logs = new File(nginxConf.getParentFile().getAbsolutePath() + File.separator + "logs");
        if (logs.exists())
            entity.setLogPath(logs.getAbsolutePath());
        entity.setExistsUpdate("true");
        settingDao.saveOrUpdate(entity);
        return new ResponseResult<>("绑定成功！");
    }

    /**
     * 解绑nginx配置
     */
    @Transaction
    @Mapping(value = "/unconfig", method = MethodType.POST)
    public Object unconfig() {
        SettingEntity entity = settingDao.findAll().get(0);
        if (StrUtil.isBlank(entity.getNginxPath())) {
            return new ResponseResult<>().fail("还未绑定对应nginx");
        }
        File oldNginx = new File(entity.getNginxPath() + File.separator + "conf" + File.separator + entity.getOldName());
        if (oldNginx.exists()) {
            File nginx = new File(oldNginx.getParentFile().getAbsolutePath() + File.separator + "nginx.conf");
            FileUtil.writeString(
                    FileUtil.readString(oldNginx, StandardCharsets.UTF_8),
                    nginx,
                    StandardCharsets.UTF_8);
            log.info("还原原来nginx：{}", oldNginx.getAbsolutePath());
        }

        entity.setNginxPath(null);
        entity.setIsInit("false");
        entity.setConfPath(null);
        entity.setConfList(null);
        entity.setLogPath(null);
        entity.setExistsUpdate("false");
        settingDao.saveOrUpdate(entity);
        TerminalUtils.stopNginx(WebApp.thread);
        ThreadUtil.sleep(1000);
        return new ResponseResult<>("解绑成功！");
    }


    /**
     * 重启服务
     */
    @Transaction
    @Mapping(value = "/restart", method = MethodType.POST)
    public Object restart() {
        SettingEntity setting = settingDao.findAll().get(0);
        if (!"true".equals(setting.getIsInit()))
            return new ResponseResult<>().fail("还未绑定nginx");
        TerminalUtils.cdNginxDir(WebApp.thread, setting.getNginxPath());
        boolean status = TerminalUtils.nginxIsRun(WebApp.thread);
        String res = "";
        if (!status) {
            // 启动
            res = TerminalUtils.startNginx(WebApp.thread);
        } else {
            // 重启
            res = TerminalUtils.stopNginx(WebApp.thread);
            log.info("停止完成: {}", res);
            ThreadUtil.sleep(1000);
            res = TerminalUtils.startNginx(WebApp.thread);
        }
        setting.setExistsUpdate("false");
        settingDao.saveOrUpdate(setting);
        log.info("重启成功: {}", res);
        ThreadUtil.sleep(1000);
        return new ResponseResult<>("重启成功！");
    }

    /**
     * 停止nginx
     */
    @Mapping(value = "/stop", method = MethodType.POST)
    public Object stop() {
        SettingEntity setting = settingDao.findAll().get(0);
        if (!"true".equals(setting.getIsInit()))
            return new ResponseResult<>().fail("还未绑定nginx");

        String res = TerminalUtils.stopNginx(WebApp.thread);
        log.info("停止完成: {}", res);
        ThreadUtil.sleep(1000);
        return new ResponseResult<>("停止nginx成功!");
    }

    @Mapping(value = "/see", method = MethodType.GET)
    public Object see(String name) {
        CheckUtils.checkNotNull(name, "配置文件名称");
        SettingEntity setting = settingDao.findAll().get(0);
        if (!"true".equals(setting.getIsInit()))
            return new ResponseResult<>().fail("还未绑定nginx");

        String content = null;
        File fileList = new File(setting.getConfList());
        for (File file : fileList.listFiles()) {
            if (file.getName().equals(name)) {
                content = FileUtil.readString(file, StandardCharsets.UTF_8);
                break;
            }
        }
        if (content == null)
            return new ResponseResult<>().fail("文件不存在: " + fileList.getAbsolutePath() + File.separator + name);
        return new ResponseResult<>(fileList.getAbsolutePath() + File.separator + name)
                .setData(content);
    }

    @Mapping(value = "/console", method = MethodType.GET)
    public Object console() {
        return new ModelAndView("console.ftl");
    }
}
